#include "StdAfx.h"

#include "ColorUtils/Color.h"
#include "ColorUtils/Image.h"
#include "MathUtils/Ray.h"
#include "FirstIntersectionResult.h"
#include "SecondIntersectionResult.h"
#include "Intersectable.h"
#include "Light.h"
#include "Scene.h"
#include "World.h"


#include "ShadedIntersectable.h"

ShadedIntersectable::ShadedIntersectable(Intersectable_ptr flatObj, Scene_ptr scene, const Color& specular, int shininess, const Color& ambient, const Color& emission, double reflectance) 
	: _flatShaded(flatObj), _scene(scene), _specular(specular), _shininess(shininess), _ambient(ambient), _emission(emission), _reflectance(reflectance)
{}

void ShadedIntersectable::WhereIntersects(const Ray& ray, FirstIntersectionResult& result)
{
	_flatShaded->WhereIntersects(ray, result);
	result.Obj = this;
}

void ShadedIntersectable::ColorAtIntersection(SecondIntersectionResult& result, const Point& point, const Ray& ray)
{
	static int numOfReflactions = 0;

	Color retColor(Point(0, 0, 0));
	Direction normalAtPoint(_flatShaded->NormalAtPoint(result, point));
	_flatShaded->ColorAtIntersection(result, point, ray);
	Point garbagePoint(0, 0, 0);

	if (normalAtPoint.ScalarProduct(ray.D) > 0)
		normalAtPoint *= -1;

	for (std::vector<Light_ptr>::iterator iter = _scene->Lights->begin(); iter != _scene->Lights->end(); iter++)
	{
		Ray lightRes = (*iter)->IntensityAtPoint(point);
		double tempMult = lightRes.D.ScalarProduct(normalAtPoint);

		if (tempMult > 0)
		{
			Color diffuseAndSpecular(result.ColorAtPoint * (tempMult)); //diffuse
			diffuseAndSpecular += _specular * pow(abs(-lightRes.D.Reflection(normalAtPoint).ScalarProduct(ray.D)), _shininess); //specular
			lightRes.P.TransMultiplication(diffuseAndSpecular);
			retColor += lightRes.P;
		}
	}


	if (_reflectance != 0 && numOfReflactions < 10)
	{
		numOfReflactions++;

		bool wasRayReflacted = result.isReflacted;
		result.isReflacted = true;

		Ray reflectionRay(point, ray.D.Reflection(normalAtPoint)); //reflection
		_scene->IntersectionFinder->WhereIntersects(reflectionRay, result);
		_scene->IntersectionFinder->ColorAtIntersection(result, garbagePoint, reflectionRay);

		retColor += result.ColorAtPoint * _reflectance;

		result.isReflacted = wasRayReflacted;

		numOfReflactions--;
	}

	Color ambientColor(_ambient); //ambient
	ambientColor.TransMultiplication(_scene->AmbientLight);
	retColor += ambientColor;

	retColor += _emission;	 //emission
	result.ColorAtPoint = retColor;
}

Direction ShadedIntersectable::NormalAtPoint(FirstIntersectionResult& result, const Point& point)
{
	return _flatShaded->NormalAtPoint(result, point);
}

ShadedIntersectable::~ShadedIntersectable() {};
